package starter

import (
	"gitee.com/sourcandy/filter/logers"
	"gitee.com/sourcandy/filter/oauth2"
	"gitee.com/sourcandy/filter/reader"
	"github.com/gin-gonic/gin"
	"github.com/robfig/cron/v3"
	"github.com/rs/zerolog/log"
	"reflect"
	"strconv"
)

const GinConfig = "ginserver"

var (
	configData *reader.Reader
	ginSrv *gin.Engine
	oauth2Srv *oauth2.OauthStarter
)

type Starter struct {
	writer    *reader.Reader
	isOpenLog bool
	es        *gin.Engine
	oauth2    *oauth2.OauthStarter
}

// CronTabObj ...
type CronTabObj struct {
	Name    string
	CronTab string
	Handler func() error
}

type InFunc func(keys reflect.Value, val any) error

// New 初始化结构体
func New(options ...reader.Option) *Starter {
	config, err := reader.NewSetting(options...)
	if err != nil {
		panic(err)
	}
	configData = config
	ginSrv = gin.Default()
	return &Starter{
		writer: config,
		es:     ginSrv,
	}
}

// InitOauth 初始化oauth2
func (s *Starter) InitOauth(info *oauth2.OauthStarter, opt ...oauth2.OauthParam) *Starter {
	info = oauth2.NewOauth2(s.writer.Get(oauth2.OauthConfig),opt...)
	s.oauth2 = info
	oauth2Srv = info
	return s
}

// UseLog 日志记录
func (s *Starter) UseLog(isOpen bool) *Starter {
	if isOpen {
		s.isOpenLog = true
		log.Logger = logers.NewLog(logers.WithWritePath(s.writer.GetStringMapString(GinConfig)["log_filepath"]),
			logers.WithLogExt(s.writer.GetStringMapString(GinConfig)["log_file_ext"])).Reader().Logger
	}
	return s
}

// BindField 绑定数据
func (s *Starter) BindField(f ...interface{}) *Starter {
	for _, i2 := range f {
		t2 := reflect.TypeOf(i2).Elem()
		v2 := reflect.ValueOf(i2).Elem()
		for i := 0; i < v2.NumField(); i++ {
			InParamMapFunc(t2.Field(i).Type.Elem().String())(v2.Field(i), s.writer.Bind(t2.Field(i).Name))
		}
	}
	return s
}

// HandleRouter 绑定路由
func (s *Starter) HandleRouter(route func(r *gin.Engine)) *Starter {
	route(s.es)
	return s
}

// HandleAddFunc 定时执行函数
func (s *Starter) HandleAddFunc(list []*CronTabObj) *Starter {
	c := cron.New(cron.WithSeconds())
	for index, crontabObj := range list {
		func(id int, obj *CronTabObj) {
			_, _ = c.AddJob(
				obj.CronTab, //一分钟
				cron.FuncJob(func() {
					_ = obj.Handler()
				}))
		}(index, crontabObj)
	}
	c.Start() //启动crond
	return s
}

// HandleMiddleware 绑定中间件
func (s *Starter) HandleMiddleware(middles ...gin.HandlerFunc) *Starter {
	s.es.Use(middles...)
	return s
}

// GetConfig 获取配置信息
func (s *Starter) GetConfig() *reader.Reader {
	return s.writer
}

// GetOauth2 获取oauth2配置信息
func (s *Starter) GetOauth2() *oauth2.OauthStarter {
	return s.oauth2
}

// GetSrv 获取gin的服务
func (s *Starter) GetSrv() *gin.Engine {
	return s.es
}

// GetConfig ...
func GetConfig() (*reader.Reader,error) {
	if configData == nil {
		return configData,ErrorNotFoundConfigInfo
	}
	return configData,nil
}

// GetOauth2Config ...
func GetOauth2Config() any {
	return configData.Get(oauth2.OauthConfig)
}

// GetGinConfig ...
func GetGinConfig() any {
	return configData.Get(GinConfig)
}

// GetSrv ...
func GetSrv() (*gin.Engine,error) {
	if ginSrv == nil {
		return ginSrv,ErrorNotFoundGinSrv
	}
	return ginSrv,nil
}

// GetOauth2 ...
func GetOauth2() (*oauth2.OauthStarter,error) {
	if oauth2Srv == nil {
		return oauth2Srv,ErrorNotFoundOauth2Srv
	}
	return oauth2Srv,nil
}

// Run 启动
func (s *Starter) Run() error {
	val := s.writer.GetStringMap(GinConfig)
	gin.SetMode(val["run_mode"].(string))
	return s.es.Run(":" + strconv.Itoa(val["http_port"].(int)))
}
